#include "../header/bib_FileSystem.h"

//Variables globales
extern struct stFILE_SYSTEM *lsFS;
extern sem_t accesoListaFS;

//Indica si el socket es del File System
int esSocketFS(int sock){
	struct stFILE_SYSTEM *punteroAct;

	sem_wait(&accesoListaFS);

	//Verificar si el socket pertenece a las lista de File System
	punteroAct=lsFS;
	while(punteroAct != NULL){
		if (punteroAct->socket==sock){
			sem_post(&accesoListaFS);
			return RESP_TRUE;
		}
		punteroAct=punteroAct->sgte;
	}
	sem_post(&accesoListaFS);

	return RESP_FALSE;
}

//Agrega un File System a la lista de FS
int agregarFileSystem(int sock){
	struct stFILE_SYSTEM *nuevoFS;

	//Reservar memoria para la estructura
	nuevoFS=(struct stFILE_SYSTEM *) malloc(sizeof(struct stFILE_SYSTEM));
	if (!nuevoFS){
		//Error de memoria
		imprimirLog(WARNING, "Memoria insuficiente para aceptar una solicitud de File System","");
		cerrarSocket(sock);
		return FIN_WARNING;
	}

	//Inicializar estructura
	nuevoFS->socket=sock;
	nuevoFS->contadorEscritura=0;

	//Colocar el FS al principio de la lista de FS
	sem_wait(&accesoListaFS);

	nuevoFS->sgte=lsFS;
	lsFS=nuevoFS;

	sem_post(&accesoListaFS);

	return FIN_OK;
}

//Inicializa la cantidad de escrituras que debe esperar antes de considerarse exitosa
void inicializarCantEsc(int sock, int valor){
	struct stFILE_SYSTEM *punteroAct;

	sem_wait(&accesoListaFS);

	//Buscar el socket
	punteroAct=lsFS;
	while(punteroAct != NULL){
		if (punteroAct->socket==sock){
			punteroAct->contadorEscritura=valor;
			sem_post(&accesoListaFS);
			return;
		}
		punteroAct=punteroAct->sgte;
	}
	sem_post(&accesoListaFS);
}

//Quitar un FS de la lista, indica si se encontro o no
int quitarFileSystemLista(int sock){
	struct stFILE_SYSTEM *ptrActual, *ptrAnterior;

	sem_wait(&accesoListaFS);

	ptrAnterior = NULL;
	ptrActual = lsFS;

	//Si no hay elementos en la lista salir
	if (lsFS==NULL){
		sem_post(&accesoListaFS);
		return RESP_FALSE;
	}

	//Determinar si es el primero de la lista
	if (lsFS->socket == sock){

		//Primero de la lista
		lsFS=ptrActual->sgte;
		free(ptrActual);
		sem_post(&accesoListaFS);

		return RESP_TRUE;

	}else{

		//Recorrer la lista
		while(ptrActual->socket != sock && ptrActual->sgte != NULL){
			ptrAnterior = ptrActual;
			ptrActual = ptrAnterior->sgte;
		}

		//Liberar solicitud de memoria
		if(ptrActual != NULL){
			if (ptrActual->socket==sock){
				ptrAnterior->sgte = ptrActual->sgte;
				free(ptrActual);
				sem_post(&accesoListaFS);

				//Informar que se desconecto inesperadamente un File System
				imprimirLogNumerico(INFO, "Se desconecto una solicitud del File System con el socket",sock);

				return RESP_TRUE;
			}
		}
	}

	//No se econtro
	sem_post(&accesoListaFS);
	return RESP_FALSE;
}

//Indica que una escritura se realizo con exito, si ocurrieron todas se responde al FS
void informarEscrituraFS(int sock, uint32_t idSolic){
	struct stFILE_SYSTEM *punteroAct;

	sem_wait(&accesoListaFS);

	//Buscar socket
	punteroAct=lsFS;

	while(punteroAct != NULL){
		if (punteroAct->socket==sock){

			//Reducir el contador de escrituras en 1
			punteroAct->contadorEscritura=punteroAct->contadorEscritura-1;

			//Si se escribio en todos los discos informar al File System
			if (punteroAct->contadorEscritura==0){
				responderEscrituraOkFS(sock,idSolic);

				//La función de quitar FS necesita el semaforo tambien
				sem_post(&accesoListaFS);
				quitarFileSystemLista(sock);
				return;
			}

			sem_post(&accesoListaFS);
			return;
		}

		//Siguiente FS
		punteroAct=punteroAct->sgte;
	}

	//No se encontro, ignorar
	sem_post(&accesoListaFS);
}

//Enviar al FS la lectura, actualizar lista y desconectar
void informarLecturaFS(int sock, struct HEADER_NIPC header, char *mensaje){
	struct stFILE_SYSTEM *punteroAct;

	sem_wait(&accesoListaFS);

	//Buscar socket
	punteroAct=lsFS;

	while(punteroAct != NULL){
		if (punteroAct->socket==sock){

			//Enviar mensaje al File System
			responderLecturaOkFS(sock, header, mensaje);

			//La función de quitar FS necesita el semaforo tambien
			sem_post(&accesoListaFS);
			quitarFileSystemLista(sock);
			return;
		}

		//Siguiente FS
		punteroAct=punteroAct->sgte;
	}

	//No se encontro, ignorar
	sem_post(&accesoListaFS);
}
